// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: gekim

#pragma once

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "coin2/exchange/base/symbology/spot_product.h"
#include "coin2/exchange/base/symbology/util.h"
#include "coin2/exchange/kucoin/symbology/currency.h"

namespace coin2::exchange::kucoin::symbology {

class KucoinProduct : public base::symbology::SpotProduct<KucoinCurrency, KucoinProduct>,
                      public base::symbology::ProductFromStrMixin<KucoinProduct> {
 public:
  typedef SpotProduct<KucoinCurrency, KucoinProduct> BaseProduct;

  KucoinProduct(const KucoinCurrency& base, const KucoinCurrency& quote)
      : SpotProduct(
            base,
            quote,
            ToKucoinNativeProduct(base, quote),
            ToKucoinNativeProduct(base, quote),
            base::market::ExchangeType::Kucoin) {}

 public:
  static std::unique_ptr<KucoinProduct> FromNativeStrImpl(
      const std::string& native_product,
      int64_t resolve_timestamp) {
    std::unique_ptr<KucoinCurrency> base_ptr;
    std::unique_ptr<KucoinCurrency> quote_ptr;
    bool success =
        ParseKucoinNativeProduct(native_product, resolve_timestamp, &base_ptr, &quote_ptr);
    if (success) {
      return std::make_unique<KucoinProduct>(*base_ptr, *quote_ptr);
    } else {
      return {};
    }
  }

 private:
  static bool ParseKucoinNativeProduct(
      const std::string& product_str,
      int64_t resolve_timestamp,
      std::unique_ptr<KucoinCurrency>* base_ptr,
      std::unique_ptr<KucoinCurrency>* quote_ptr) {
    static const std::unordered_map<std::string, std::string> map = {
        {"BCHSV", "BSV"},
        {"GALAX", "GALA"},
        {"LOKI", "OXEN"},
        {"R", "REV"},
        {"WAX", "WAXP"},
        {"ETH2", "KSETH"},
    };
    const std::string& product_str_lower = product_str;
    std::vector<std::string> splitted;
    splitted = Split(product_str_lower, "-");
    if (splitted.size() != 2) {
      return false;
    }

    if (map.count(splitted[0]) > 0) {
      *base_ptr = KucoinCurrency::FromNativeStrNoThrow(map.at(splitted[0]), resolve_timestamp);
    } else {
      *base_ptr = KucoinCurrency::FromNativeStrNoThrow(splitted[0], resolve_timestamp);
    }

    if (map.count(splitted[1]) > 0) {
      *quote_ptr = KucoinCurrency::FromNativeStrNoThrow(map.at(splitted[1]), resolve_timestamp);
    } else {
      *quote_ptr = KucoinCurrency::FromNativeStrNoThrow(splitted[1], resolve_timestamp);
    }
    return true;
  }

  static std::string ToKucoinNativeProduct(
      const KucoinCurrency& base,
      const KucoinCurrency& quote) {
    using base::market::MarketType;
    static const std::unordered_map<std::string, std::string> map = {
        {"BSV", "BCHSV"},
        {"GALA", "GALAX"},
        {"OXEN", "LOKI"},
        {"REV", "R"},
        {"WAXP", "WAX"},
        {"KSETH", "ETH2"},
    };
    std::string b = base.native_currency(MarketType::Spot);
    std::string q = quote.native_currency(MarketType::Spot);

    if (map.count(b) > 0) {
      b = map.at(b);
    }
    if (map.count(q) > 0) {
      q = map.at(q);
    }
    return b + "-" + q;
  }
};

}  // namespace coin2::exchange::kucoin::symbology
